#ifndef __CM_XMPP_CONNECTION_H__
#define __CM_XMPP_CONNECTION_H__

#include "Poco/Runnable.h"
#include "Poco/Thread.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/PriorityNotificationQueue.h"

#include "cm_base/ByteBuffer.h"
#include "cm_base/ByteBufferPool.h"

#include "ConnectionDataHandler.h"

using Poco::Runnable;
using Poco::Thread;
using Poco::PriorityNotificationQueue;

using Poco::Net::SocketAddress;
using Poco::Net::SocketReactor;
using Poco::Net::StreamSocket;
using Poco::Net::SecureStreamSocket;
using Poco::Net::ReadableNotification;
using Poco::Net::ErrorNotification;

using cm_base::ByteBuffer;
using cm_base::ByteBufferPool;

namespace cm_xmpp
{
    class Connection: public Runnable
    {
    public:
        enum{
            ConnNoError,
            ConnTLSError
        };

        enum{
            EVENT_SEND,
            EVENT_RECEIVED, 
            EVENT_TEARDOWN
        };

        enum{
            QUEUE_PRI_HIGH = 0,
            QUEUE_PRI_LOW  = 2
        };

        Connection(ByteBufferPool* pool);
        virtual ~Connection();

        int setup();
        int teardown();

        void setServer(const SocketAddress& sa);
        void registerDataHandler( ConnectionDataHandler* dataHandler );

        /**
        * create non-SSL connection
        */
        bool connect();
        /**
        * negotiate ssl
        */
        bool setupSSL(std::string serverName);

        bool disconnect();
        void cleanup();

        bool send(ByteBuffer * data);
        bool send(const std::string& data);

        /**
        * Call back for SocketReactor
        */
        void handleReceive( ReadableNotification* rn);
        void handleError( ErrorNotification* en);

        /**
        * Returns the current connection state.
        * @return The state of the connection.
        */
        int state();
        /**
        * From Runnable, send out and dispatch data 
        */
        void run();

    private:
        int doRecv();
        int doSend( ByteBuffer* data );
        int handleReceivedData( ByteBuffer* p_data );

        int doTeardown();

    protected:
        ByteBufferPool* m_buffer_pool;

        //handle received data 
        //and other connection info from lower layer
        ConnectionDataHandler* m_dataHandler;
        PriorityNotificationQueue m_queue;

        SocketAddress m_sa;
        StreamSocket m_socket;
        SecureStreamSocket m_sslsocket;

        SocketReactor m_reactor;

        Thread m_reactorThread;
        Thread m_workThread;

        int  m_state;

        bool m_stopFlag;
        bool m_ssldFlag;

    };
}

#endif